#include "Strat.hpp"
#include "world.hpp"
#include "Ai.hpp"
#include <iostream>
#include "murder.h"
#include "collect.h"
#include "helper.h"

#define SEUIL_MIN_ACTION 100

#define RAYON_PROXIMITE  3

//globale
pathfinder<World,map_chunk> pf(&ai.world);
map_chunk *astart;
map_chunk *aend;
list<map_chunk*> path;


enum {
    needPvMiner,
    needSugarMiner,
    needDefenseArbre,
    needDefenseSource,
    needDefenseBase,
    needAttackArbre,
    needAttackSource,
    needAttackBase,
    needHealer,
    needMax
};

Strat::Strat(){
     time=0;
     myPv=0;
     goalPv=0;
     myPopulation=0;
     ennemyPopulation=0;
     maxPopulation=0;
     mySugar=0;
     nbrSugarMiner=0;
     nbrPvMiner=0;
     defenseArbre=0;
     defenseBase=0;
     defenseSource=0;
     dangerArbre=0;
     dangerBase=0;
     dangerSource=0;
     nbrHealer=0;
     generalHealth=0;
     nbrAttacker=0;
     nbrPotentialIdler=0;
     iaActive=1;
     allowCreationOfCherry=0;
     allowCreationOfKiwi=0;
     allowCreationOfNut=0;
}




void Strat::run() {
    allowCreationOfCherry=0;
    allowCreationOfKiwi=0;
    allowCreationOfNut=0;
    calculate();
    playTurn();

    calculate();
    playTurn();

    //while(allowCreationOfCherry) fructify(quelquundelibre, FRUIT_CHERRY, int x, int y);
    }



void Strat::playTurn() {

    for( map<int,Fruit>::iterator it = ai.world.ourFruits.begin(); it != ai.world.ourFruits.end(); it++ ){
        //it->second.task.mustFlee();
        it->second.task->needResupply();
        bool ret = it->second.task->execute();
        it->second.task->loot();
        cout << "play: (type)" << it->second.task->type << " bool " << ret << " PV: "<<it->second.vitamins << endl;
    }

}


void Strat::init() {

}

void Strat::calculate() {


    //script à l'arrache**********
    majParam();
    if(ai.curTurn>0)
    {
        iaActive=0;


        //caca cerise
        if(myPv>ai.curTurn && myPopulation<=5)
        {
            map_chunk* spawn = getFreeSpaceAround(ai.world.ourFructificationTank.position);

            ai.world.fructify(FRUIT_CHERRY,spawn->X_coord,spawn->Y_coord);

        }



        //selectionner le kiwi et attaquer un adversaire
            for( map<int,Fruit>::iterator it = ai.world.ourFruits.begin(); it != ai.world.ourFruits.end(); it++ ){
                if(it->second.task->type==T_IDLE)
                {
                    delete it->second.task;
                    map_chunk* pepe= ai.world.theVitaminSource.position;
                    it->second.task=new Collect(&it->second, pepe->X_coord,pepe->Y_coord, VIT);
                }

                //if(it->second.getType()==FRUIT_CHERRY)

                /*
                {
                    delete it->second.task;
                    it->second.task=new Murder(&it->second, (int)ai.world.theirFruits.begin()->second.id);

                }

                {
                    delete it->second.task;
                    map_chunk* pepe= getFreeSpaceAround(ai.world.theVitaminSource.position);
                    cout << "pos pepe : " << pepe->X_coord << "/"<< pepe->Y_coord <<   endl;
                    it->second.task=new Collect(&it->second, ai.world.theVitaminSource.position->X_coord,ai.world.theVitaminSource.position->Y_coord, VIT);
                }
                */

            }

        //tasker les fruits


    }
    if(time==1000)
    {
        iaActive=1;
    }


    //actions automatiques
    if(iaActive)
    {

        //meta
        float need[needMax];
        int i,m=0;
        Fruit* unit;
        for(i=0;i<needMax;i++) need[i]=0;

        //local à l'unité
        //int needFlee=0, needSupply=0;
        //changement d'état effectué par l'unité elle même


        int actionDone=0;
        do{
            //calcul des besoins
            need[needPvMiner]=(0.3-nbrPvMiner/myPopulation);
            need[needSugarMiner]=(0.1-nbrSugarMiner/myPopulation)*nbrAttacker;
            need[needDefenseArbre]= (dangerArbre-defenseArbre) + (0.05-defenseArbre/myPopulation);
            need[needDefenseSource]= (dangerSource-defenseSource)+ (0.05-defenseSource/myPopulation);
            need[needDefenseBase]=(dangerBase-defenseBase)+ (0.05-defenseSource/myPopulation);
            need[needAttackArbre]=dangerArbre;
            need[needAttackSource]=dangerSource;
            need[needAttackBase]=dangerBase;
            need[needHealer]= (1 - generalHealth) + (1 - nbrHealer/myPopulation);

            //remise à l'echelle
            need[needPvMiner]*=1;
            need[needPvMiner]*=1;
            need[needSugarMiner]*=1;
            need[needDefenseArbre]*=1;
            need[needDefenseSource]*=1;
            need[needDefenseBase]*=1;
            need[needAttackArbre]*=1;
            need[needAttackSource]*=1;
            need[needAttackBase]*=1;
            need[needHealer]*=1;


            //choix du maximum
            for(i=0;i<needMax;i++){
                if(need[i]>need[m]) m=i;
            }
            actionDone=1;
            if(need[m]<SEUIL_MIN_ACTION)
            {
                m=-1;
            }
            else{


                //si pas d'unité, demander sa creation
                if(nbrPotentialIdler<0)
                {
                    int estimateur = myPv/goalPv ;
                    int seuil = 1;
                    if(time<timeOut*3/4 && estimateur<seuil) //if on veut vraiment créer une unité
                    {
                        allowCreationOfCherry++;
                    }

                    actionDone=0;
                }
                else{

                    //choix de l'unité
                    unit=chooseUnit(m);

                    //tentative d'affectation
                    switch(m)
                    {
                        case needPvMiner:
                            //delete unit->task;
                            //unit->task=new Collect();
                        break;

                        default: //si rien n'est à faire
                            actionDone=0;
                        break;
                    }

                    //si tout s'est bien passé
                    majParam();
                }
            }


        } while(actionDone);
    }
}



Fruit* Strat::chooseUnit(int a)
{
    for( map<int,Fruit>::iterator it = ai.world.ourFruits.begin(); it != ai.world.ourFruits.end(); it++ ){
                if(it->second.task->type == T_IDLE)
                return(&it->second);
    }

    return &(ai.world.ourFruits.begin()->second);
}

bool closeTo(Building batiment, int x, int y);

void Strat::majParam(void) {


    //ai.world.at(0,0).buildin

    time = ai.curTurn;
    timeOut = ai.limTurns;
    myPv = ai.world.getVitaminCount();
    goalPv = ai.limVitamines;
    myPopulation =ai.world.ourFruits.size();
    ennemyPopulation = ai.world.theirFruits.size();
    maxPopulation = ai.world.maxKiwis + ai.world.maxCherries + ai.world.maxNuts;
    mySugar = ai.world.getSugarCount();

    nbrSugarMiner = 0;
    nbrPvMiner = 0;
    defenseArbre = 0;
    defenseBase = 0;
    defenseSource = 0;
    dangerArbre = 0;
    dangerBase = 0;
    dangerSource = 0;
    nbrHealer = 0;
    generalHealth = 0;
    nbrAttacker = 0;
    nbrPotentialIdler = 0;

    Fruit *pointeurSurFruit;
    int number;

    for( map<int, Fruit>::iterator it = ai.world.ourFruits.begin(); it != ai.world.ourFruits.end(); it++ )
    {
        pointeurSurFruit = &it->second;

        if(pointeurSurFruit->task->type == T_IDLE)           nbrPotentialIdler++;
        else if(pointeurSurFruit->task->type == T_MURDER)    nbrAttacker++;
        else if(pointeurSurFruit->task->type == T_HITANDRUN) nbrAttacker++;
        else if(pointeurSurFruit->task->type == T_LOOT)      nbrSugarMiner++;
        else if(pointeurSurFruit->task->type == T_COLLECT)   nbrPvMiner++;
        else if(pointeurSurFruit->task->type == T_ATTACK)    nbrAttacker++;
        else if(pointeurSurFruit->task->type == T_GUARD)
        {
            if(closeTo(ai.world.ourJuiceBarrel,pointeurSurFruit->position->X_coord, pointeurSurFruit->position->Y_coord))    defenseBase++;
            else if(closeTo(ai.world.ourSugarBowl,pointeurSurFruit->position->X_coord, pointeurSurFruit->position->Y_coord))    defenseBase++;
            else if(closeTo(ai.world.ourFructificationTank,pointeurSurFruit->position->X_coord, pointeurSurFruit->position->Y_coord))    defenseBase++;
            else if(closeTo(ai.world.theVitaminSource,pointeurSurFruit->position->X_coord, pointeurSurFruit->position->Y_coord))    defenseSource++;
            else if(closeTo(ai.world.theSugarTree,pointeurSurFruit->position->X_coord, pointeurSurFruit->position->Y_coord))    defenseArbre++;
        }
        else if(pointeurSurFruit->task->type == T_HEAL)      nbrHealer++;

        generalHealth += pointeurSurFruit->life/pointeurSurFruit->maxLife;
        number++;
    }
    generalHealth /= number;

    for( map<int, Fruit>::iterator it = ai.world.theirFruits.begin(); it != ai.world.theirFruits.end(); it++ )
    {
        pointeurSurFruit = &it->second;

        if(closeTo(ai.world.ourJuiceBarrel,pointeurSurFruit->position->X_coord, pointeurSurFruit->position->Y_coord))    dangerBase++;
        else if(closeTo(ai.world.ourSugarBowl,pointeurSurFruit->position->X_coord, pointeurSurFruit->position->Y_coord))    dangerBase++;
        else if(closeTo(ai.world.ourFructificationTank,pointeurSurFruit->position->X_coord, pointeurSurFruit->position->Y_coord))    dangerBase++;
        else if(closeTo(ai.world.theVitaminSource,pointeurSurFruit->position->X_coord, pointeurSurFruit->position->Y_coord))    dangerSource++;
        else if(closeTo(ai.world.theSugarTree,pointeurSurFruit->position->X_coord, pointeurSurFruit->position->Y_coord))    dangerArbre++;
    }
}

bool closeTo(Building batiment, int x, int y)
{
    if(batiment.position->X_coord + RAYON_PROXIMITE > x && batiment.position->X_coord - RAYON_PROXIMITE < x)
    {
        if(batiment.position->Y_coord + RAYON_PROXIMITE > y && batiment.position->Y_coord - RAYON_PROXIMITE < y)
        {
            return true;
        }
    }

    return false;
}
